//
//  TTCoreNetwork.m
//  Tint
//
//  Created by Kevin Wu on 2/22/12.
//  Copyright (c) 2012 Telligenty. All rights reserved.
//

#import "TTCoreNetwork.h"
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>
#import "TTMacro.h"


#pragma mark - Network availability

BOOL TTIsNetworkAvailable(void) {
    TTNetworkStatus status = TTGetNetworkStatus();
    return ((status == TTNetworkStatusAvailableViaWiFi) || (status == TTNetworkStatusAvailableViaWWAN));
}

BOOL TTIsNetworkAvailableViaWiFi(void) {
    TTNetworkStatus status = TTGetNetworkStatus();
    return (status == TTNetworkStatusAvailableViaWiFi);
}

BOOL TTIsNetworkAvailableViaWWAN(void) {
    TTNetworkStatus status = TTGetNetworkStatus();
    return (status == TTNetworkStatusAvailableViaWWAN);
}

TTNetworkStatus TTGetNetworkStatus(void) {
    
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    
    SCNetworkReachabilityFlags flags;
    BOOL gotFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    TTReleaseCF(defaultRouteReachability);
    
    if (gotFlags && (flags & kSCNetworkReachabilityFlagsReachable)) {
        
        // Observed WWAN Values:
        // WWAN Active:              Reachability Flag Status: WR -t-----
        // WWAN Connection required: Reachability Flag Status: WR ct-----
        //
        // Test Value: Reachability Flag Status: WR xxxxxxx
        if (flags & kSCNetworkReachabilityFlagsIsWWAN) { return TTNetworkStatusAvailableViaWWAN; }
        
        // Clear moot bits.
        flags &= ~kSCNetworkReachabilityFlagsReachable;
        flags &= ~kSCNetworkReachabilityFlagsIsDirect;
        flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress; // kInternetConnection is local.
        
        // Reachability Flag Status: -R ct---xx Connection down.
        SCNetworkReachabilityFlags connectionDown =  kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection;
        if (flags == connectionDown) { return TTNetworkStatusNotAvailable; }
        
        // Reachability Flag Status: -R -t---xx Reachable. WiFi + VPN(is up) (Thank you Ling Wang)
        if (flags & kSCNetworkReachabilityFlagsTransientConnection)  { return TTNetworkStatusAvailableViaWiFi; }
        
        // Reachability Flag Status: -R -----xx Reachable.
        if (flags == 0) { return TTNetworkStatusAvailableViaWiFi; }
        
        // Apple's code tests for dynamic connection types here. I don't. 
        // If a connection is required, regardless of whether it is on demand or not, it is a WiFi connection.
        // If you care whether a connection needs to be brought up,   use -isConnectionRequired.
        // If you care about whether user intervention is necessary,  use -isInterventionRequired.
        // If you care about dynamically establishing the connection, use -isConnectionIsOnDemand.
        
        // Reachability Flag Status: -R cxxxxxx Reachable.
        if (flags & kSCNetworkReachabilityFlagsConnectionRequired) { return TTNetworkStatusAvailableViaWiFi; }
    }
    
    return TTNetworkStatusNotAvailable;
}
